﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;

namespace Isuka.Collections
{
    public class LimitedQueue<T>
        : IEnumerable<T>
    {
        readonly int maxitems;
        readonly LinkedList<T> inner;

        public LimitedQueue(int maxitems)
        {
            Contract.Requires<ArgumentOutOfRangeException>(0 < maxitems, "maxitems");
            this.maxitems = maxitems;
            this.inner = new LinkedList<T>();
        }

        public int Count
        {
            get { return inner.Count; }
        }

        public T ForceEnqueue(T item)
        {
            Contract.Ensures(inner.Count <= maxitems);

            while (maxitems <= inner.Count)
            {
                Dequeue();
            }
            inner.AddLast(item);
            return item;
        }

        public T Dequeue()
        {
            Contract.Ensures(inner.Count == 0 || inner.Count == Contract.OldValue<int>(inner.Count) - 1);

            if (inner.Count <= 0)
            {
                throw new InvalidOperationException();
            }
            var first = inner.First.Value;
            inner.RemoveFirst();
            return first;
        }

        #region IEnumerable<T> メンバー

        public IEnumerator<T> GetEnumerator()
        {
            return inner.GetEnumerator();
        }

        #endregion

        #region IEnumerable メンバー

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return inner.GetEnumerator();
        }

        #endregion

        #region ContractInvariantMethod

        [ContractInvariantMethod]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        private void ObjectInvariant()
        {
            Contract.Invariant(inner != null);
            Contract.Invariant(inner.Count <= maxitems);
        }

        #endregion
    }
}
